package eda.skipList;

import static org.junit.Assert.*;

import java.util.NoSuchElementException;

import junit.framework.Assert;

import org.junit.After;
import org.junit.AfterClass;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Test;

import eda.util.ADTOverflowException;
import eda.util.ADTUnderflowException;

public class SkipListImplTest {
	
	private static final Object Object = null;
	boolean USE_MAX_LEVEL;
	int MAX_LEVEL_DEFAULT;
	SkipListImpl lista;
	
	/**
	 * @throws java.lang.Exception
	 */
	@Before
	public void setUp() throws Exception {
		USE_MAX_LEVEL = false;
		MAX_LEVEL_DEFAULT = 10;
		lista = new SkipListImpl(MAX_LEVEL_DEFAULT, USE_MAX_LEVEL);
	}

	/**
	 * Test method for {@link eda.skipList.SkipListImpl#insert(int, java.lang.Object)}.
	 * @throws ADTOverflowException 
	 * @throws ADTUnderflowException 
	 */
	@Test(expected=ADTOverflowException.class)
	public void testInsertIntV() throws ADTOverflowException, ADTUnderflowException {
		lista.insert(1, 1);
		lista.insert(2, 2);
		Assert.assertEquals(2, lista.size());
		lista.insert(3, 3);
		lista.insert(4, 4);
		Assert.assertEquals(4, lista.size());
		lista.insert(4, 5);
		Assert.assertEquals(4, lista.size());
		lista.insert(5, 5);
		lista.insert(6, 6);
		lista.insert(7, 7);
		lista.insert(8, 8);
		Assert.assertEquals(8, lista.size());
		lista.insert(9, 9);
		lista.insert(10, 10);
		for (int i=11; i<100; i++){
			lista.insert(i, 20);
		}
		Assert.assertEquals(99, lista.size());
		lista.insert(100, 100);
		lista.insert(101, 101);
	}

	/**
	 * Test method for {@link eda.skipList.SkipListImpl#insert(int, java.lang.Object, int)}.
	 * @throws ADTOverflowException 
	 * @throws ADTUnderflowException 
	 */
	@Test(expected=ADTOverflowException.class)
	public void testInsertIntVInt() throws ADTOverflowException, ADTUnderflowException {
		lista.insert(1, 1, 3);
		lista.insert(2, 2, 1);
		Assert.assertEquals(2, lista.size());
		lista.insert(3, 3, 4);
		lista.insert(4, 4, 6);
		Assert.assertEquals(4, lista.size());
		lista.insert(4, 5, 7);
		Assert.assertEquals(4, lista.size());
		lista.insert(5, 5, 7);
		lista.insert(6, 6, 8);
		lista.insert(7, 7, 2);
		lista.insert(8, 8, 1);
		Assert.assertEquals(8, lista.size());
		lista.insert(9, 9, 1);
		lista.insert(10, 10, 3);
		for (int i=11; i<100; i++){
			lista.insert(i, 20);
		}
		Assert.assertEquals(99, lista.size());
		lista.insert(100, 100, 4);
		lista.insert(101, 101, 1);
	}

	/**
	 * Test method for {@link eda.skipList.SkipListImpl#remove(int)}.
	 * @throws ADTOverflowException 
	 * @throws ADTUnderflowException 
	 * @throws NoSuchElementException 
	 */
	@Test(expected=ADTUnderflowException.class)
	public void testRemove1() throws ADTOverflowException, NoSuchElementException, ADTUnderflowException {
		lista.insert(1, 1);
		lista.insert(2, 2);
		lista.insert(3, 3);
		lista.remove(1);
		Assert.assertEquals(2, lista.size());
		lista.remove(2);
		lista.remove(-3);
	}
	
	@Test(expected=NoSuchElementException.class)
	public void testRemove2() throws ADTOverflowException, NoSuchElementException, ADTUnderflowException{
		lista.insert(1, 1);
		lista.insert(2, 2);
		lista.remove(2);
		lista.remove(3);
	}

	/**
	 * Test method for {@link eda.skipList.SkipListImpl#getHeight()}.
	 * @throws ADTOverflowException 
	 * @throws ADTUnderflowException 
	 */
	@Test
	public void testGetHeight() throws ADTOverflowException, ADTUnderflowException {
		lista.insert(1, 1, 3);
		lista.insert(2, 2, 1);
		lista.insert(3, 3, 4);
		lista.insert(4, 4, 6);
		lista.insert(5, 5, 7);
		lista.insert(6, 6, 8);
		Assert.assertEquals(8, lista.getHeight());
	}

	/**
	 * Test method for {@link eda.skipList.SkipListImpl#search(int)}.
	 * @throws ADTOverflowException 
	 * @throws ADTUnderflowException 
	 */
	@Test
	public void testSearch() throws ADTOverflowException, ADTUnderflowException {
		lista.insert(1, "um", 3);
		lista.insert(2, "dois", 6);
		lista.insert(3, "tres", 7);
		Assert.assertEquals("<1,3>(2,2,2)", lista.search(1).toString());
		Assert.assertEquals("<2,6>(3,3,3,3,3,3)", lista.search(2).toString());
		Assert.assertNotSame("<2,6>(3,3,3,3,3,3)", lista.search(3).toString());
	}

	/**
	 * Test method for {@link eda.skipList.SkipListImpl#printSkipList()}.
	 * @throws ADTOverflowException 
	 * @throws ADTUnderflowException 
	 * @throws NoSuchElementException 
	 */
	@Test
	public void testPrintSkipList() throws ADTOverflowException, NoSuchElementException, ADTUnderflowException {
		lista.insert(1, 1, 3);
		lista.insert(2, 2, 1);
		lista.insert(3, 3, 4);
		lista.insert(4, 4, 6);
		lista.insert(5, 5, 7);
		lista.insert(6, 6, 8);
		Assert.assertEquals("<ROOT,10>(1,1,1,3,4,4,5,6) <1,3>(2,3,3) <2,1>(3) <3,4>(4,4,4,4) " +
				"<4,6>(5,5,5,5,5,5) <5,7>(6,6,6,6,6,6,6) <6,8>(NIL,NIL,NIL,NIL,NIL,NIL,NIL,NIL)", 
				lista.printSkipList());
		lista.remove(6);
		lista.remove(5);
		Assert.assertNotSame("<ROOT,10>(1,1,1,3,4,4,5,6) <1,3>(2,3,3) <2,1>(3) <3,4>(4,4,4,4) " +
				"<4,6>(5,5,5,5,5,5) <5,7>(6,6,6,6,6,6,6) <6,8>(NIL,NIL,NIL,NIL,NIL,NIL,NIL,NIL)", 
				lista.printSkipList());
		lista.insert(7, 7, 5);
		lista.insert(8, 8, 9);
		lista.insert(9, 9, 1);
		lista.insert(10, 10, 3);
		Assert.assertEquals("<ROOT,10>(1,1,1,3,4,4,8,8,8) " +
				"<1,3>(2,3,3) <2,1>(3) <3,4>(4,4,4,4) " +
				"<4,6>(7,7,7,7,7,8) <7,5>(8,8,8,8,8) " +
				"<8,9>(9,10,10,NIL,NIL,NIL,NIL,NIL,NIL) <9,1>(10) <10,3>(NIL,NIL,NIL)", 
				lista.printSkipList());
	}

	/**
	 * Test method for {@link eda.skipList.SkipListImpl#isEmpty()}.
	 * @throws ADTOverflowException 
	 * @throws ADTUnderflowException 
	 * @throws NoSuchElementException 
	 */
	@Test
	public void testIsEmpty() throws ADTOverflowException, NoSuchElementException, ADTUnderflowException {
		Assert.assertEquals(true, lista.isEmpty());
		lista.insert(1, 1);
		lista.insert(2, 2);
		lista.insert(3, 3);
		Assert.assertEquals(false, lista.isEmpty());
		lista.remove(1);
		lista.remove(2);
		lista.remove(3);
		Assert.assertEquals(true, lista.isEmpty());
	}

	/**
	 * Test method for {@link eda.skipList.SkipListImpl#size()}.
	 * @throws ADTOverflowException 
	 * @throws ADTUnderflowException 
	 * @throws NoSuchElementException 
	 */
	@Test
	public void testSize() throws ADTOverflowException, NoSuchElementException, ADTUnderflowException {
		lista.insert(1, 1);
		lista.insert(2, 2);
		lista.insert(3, 3);
		Assert.assertEquals(3, lista.size());
		lista.insert(4, 4);
		lista.insert(5, 5);
		Assert.assertEquals(5, lista.size());
		lista.remove(3);
		Assert.assertEquals(4, lista.size());
	}

}